home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2007 December / PCWKCD1207B.iso / Blogowanie poza sfera / Flock 0.9.1.3 stable / flock-0.9.1.3.en-US.win32.exe / flock / chrome / browser.jar / content / browser / search / search.xml < prev    next >
Extensible Markup Language  |  2007-07-18  |  34KB  |  836 lines

  1. <?xml version="1.0"?>
  2.  
  3. <!DOCTYPE bindings [
  4. <!ENTITY % searchBarDTD SYSTEM "chrome://browser/locale/searchbar.dtd" >
  5. %searchBarDTD;
  6. <!ENTITY % globalDTD SYSTEM "chrome://global/locale/global.dtd">
  7. %globalDTD;
  8. <!ENTITY % flockSearchDTD SYSTEM "chrome://flock/locale/search/search.dtd">
  9. %flockSearchDTD;
  10. ]>
  11.  
  12. <bindings id="SearchBindings"
  13.       xmlns="http://www.mozilla.org/xbl"
  14.       xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
  15.       xmlns:xbl="http://www.mozilla.org/xbl">
  16.  
  17.   <binding id="searchbar-base">
  18.     <resources>
  19.       <stylesheet src="chrome://browser/content/search/searchbarBindings.css"/>
  20.       <stylesheet src="chrome://browser/skin/searchbar.css"/>
  21.     </resources>
  22.   </binding>
  23.  
  24.   <binding id="searchbar"
  25.            extends="chrome://browser/content/search/search.xml#searchbar-base">
  26.     <content>
  27.       <xul:stringbundle src="chrome://browser/locale/search.properties"
  28.                         anonid="searchbar-stringbundle"/>
  29.  
  30.       <xul:hbox class="searchbar-box" flex="1">
  31.         <xul:hbox flex="1">
  32.           <xul:button class="searchbar-engine-button"
  33.                       type="menu"
  34.                       anonid="searchbar-engine-button"
  35.                       popup="_child"
  36.                       xbl:inherits="src">
  37.             <xul:menupopup class="searchbar-popup"
  38.                            anonid="searchbar-popup"
  39.                            position="after_start">
  40.               <xul:menuseparator/>
  41.               <xul:menuitem class="open-engine-manager"
  42.                             anonid="open-engine-manager"
  43.                             label="&flock.search.cmd_engineManager.label;"
  44.                             accesskey="&cmd_engineManager.accesskey;"/>
  45.             </xul:menupopup>
  46.           </xul:button>
  47.   
  48.           <xul:textbox class="searchbar-textbox"
  49.                        anonid="searchbar-textbox"
  50.                        flex="1"
  51.                        autocompletepopup="PopupAutoComplete"
  52.                        timeout="250"
  53.                        xbl:inherits="disabled,disableautocomplete,searchengine,src">
  54.           </xul:textbox>
  55.           <xul:toolbarbutton class="flyout-dropmarker" oncommand="searchFlyout.toggle();"/>
  56.         </xul:hbox>
  57.  
  58.         <xul:stack class="search-go-button-stack">
  59.           <xul:vbox>
  60.             <!-- These image segments allow the button's gradient to stretch
  61.                  nicely in larger urlbars. -->
  62.             <xul:image class="search-go-button-top search-go-button-bkgnd"
  63.                        chromedir="&locale.dir;"/>
  64.             <xul:image flex="1"
  65.                        class="search-go-button-mid-top search-go-button-bkgnd"
  66.                        chromedir="&locale.dir;"/>
  67.             <xul:image flex="1"
  68.                        class="search-go-button-mid-bottom search-go-button-bkgnd"
  69.                        chromedir="&locale.dir;"/>
  70.             <xul:image class="search-go-button-bottom search-go-button-bkgnd"
  71.                        chromedir="&locale.dir;"/>
  72.           </xul:vbox>
  73.           <xul:toolbarbutton class="search-go-button"
  74.                              anonid="search-go-button"
  75.                              chromedir="&locale.dir;"
  76.                              label="&searchEndCap.label;" />
  77.         </xul:stack>
  78.       </xul:hbox>
  79.     </content>
  80.     <implementation implements="nsIObserver">
  81.  
  82.       <constructor><![CDATA[
  83.         if (this.parentNode.parentNode.localName == "toolbarpaletteitem")
  84.           return;
  85.         setTimeout(function (a) { a.init(); }, 0, this);
  86.       ]]></constructor>
  87.  
  88.       <method name="init">
  89.         <body><![CDATA[
  90.           // Refresh the display (updating icon, etc)
  91.           this.rebuildPopup();
  92.           this.updateDisplay();
  93.           this._textbox._displayCurrentEngine();
  94.  
  95.           var os =
  96.                Components.classes["@mozilla.org/observer-service;1"]
  97.                          .getService(Components.interfaces.nsIObserverService);
  98.           os.addObserver(this, "browser-search-engine-modified", false);
  99.         ]]></body>
  100.       </method>
  101.  
  102.       <destructor><![CDATA[
  103.         var os = Components.classes["@mozilla.org/observer-service;1"]
  104.                            .getService(Components.interfaces.nsIObserverService);
  105.         os.removeObserver(this, "browser-search-engine-modified");
  106.  
  107.         // Make sure to break the cycle from _texbox to us.  Otherwise we leak
  108.         // the world.
  109.         this._textbox.mController.input = null;
  110.       ]]></destructor>
  111.  
  112.       <field name="_stringBundle">document.getAnonymousElementByAttribute(this, 
  113.           "anonid", "searchbar-stringbundle");</field>
  114.       <field name="_textbox">document.getAnonymousElementByAttribute(this, 
  115.           "anonid", "searchbar-textbox");</field>
  116.       <field name="_popup">document.getAnonymousElementByAttribute(this, 
  117.           "anonid", "searchbar-popup");</field>
  118.       <field name="_engineButton">document.getAnonymousElementByAttribute(
  119.           this, "anonid", "searchbar-engine-button");</field>
  120.       <field name="_ss">null</field>
  121.       <field name="_engines">null</field>
  122.  
  123.       <property name="currentEngine"
  124.                 onset="this.searchService.currentEngine = val; return val;">
  125.         <getter><![CDATA[
  126.           var currentEngine = this.searchService.currentEngine;
  127.           // Return a dummy engine if there is no currentEngine
  128.           return currentEngine || {name:"", uri:null};
  129.         ]]></getter>
  130.       </property>
  131.       
  132.       <!-- textbox is used by sanitize.js to clear the undo history when 
  133.       clearing form information. -->      
  134.       <property name="textbox" readonly="true"
  135.                 onget="return this._textbox;"/>
  136.  
  137.       <property name="searchService" readonly="true">
  138.         <getter><![CDATA[
  139.           if (!this._ss) {
  140.             const nsIBSS = Components.interfaces.nsIBrowserSearchService;
  141.             this._ss =
  142.                  Components.classes["@mozilla.org/browser/search-service;1"]
  143.                            .getService(nsIBSS);
  144.           }
  145.           return this._ss;
  146.         ]]></getter>
  147.       </property>
  148.  
  149.       <property name="value"
  150.                 onget="return this._textbox.value;">
  151.         <setter><![CDATA[
  152.           // Make sure to remove the "empty" attribute if someone is setting
  153.           // the search bar value to a non-empty string. Similarly, we need to
  154.           // add the "empty" attribute if someone is clearing the search box,
  155.           // but only if the search box currently doesn't have focus.
  156.           if (val) {
  157.             this.removeAttribute("empty");
  158.             this._textbox.value = val;
  159.           }
  160.           else {
  161.             if (this._textbox.hasAttribute("focused")) {
  162.               // Just clear the textbox
  163.               this._textbox.value = "";
  164.             }
  165.             else {
  166.               // Display the current engine
  167.               this._textbox._displayCurrentEngine();
  168.             }
  169.           }
  170.  
  171.           return val;
  172.         ]]></setter>
  173.       </property>
  174.  
  175.       <method name="focus">
  176.         <body><![CDATA[
  177.           this._textbox.focus();
  178.         ]]></body>
  179.       </method>
  180.  
  181.       <method name="select">
  182.         <body><![CDATA[
  183.           this._textbox.select();
  184.         ]]></body>
  185.       </method>
  186.  
  187.       <method name="observe">
  188.         <parameter name="aEngine"/>
  189.         <parameter name="aTopic"/>
  190.         <parameter name="aVerb"/>
  191.         <body><![CDATA[
  192.           if (aTopic == "browser-search-engine-modified") {
  193.             switch (aVerb) {
  194.             case "engine-removed":
  195.               this.offerNewEngine(aEngine);
  196.               break;
  197.             case "engine-added":
  198.               this.hideNewEngine(aEngine);
  199.               break;
  200.             case "engine-current":
  201.               // The current engine was changed.  Rebuilding the menu appears to
  202.               // confuse its idea of whether it should be open when it's just
  203.               // been clicked, so we force it to close now.
  204.               this._popup.hidePopup();
  205.               break;
  206.             case "engine-changed":
  207.               // An engine was removed (or hidden) or added, or an icon was
  208.               // changed.  Do nothing special.
  209.             }
  210.  
  211.             // Rebuild the popup and update the display after any modification.
  212.             this.rebuildPopup();
  213.             this.updateDisplay();
  214.           }
  215.         ]]></body>
  216.       </method>
  217.  
  218.       <!-- There are two seaprate lists of search engines, whose uses intersect
  219.       in this file.  The search service (nsIBrowserSearchService and
  220.       nsSearchService.js) maintains a list of Engine objects which is used to
  221.       populate the searchbox list of available engines and to perform queries.
  222.       That list is accessed here via this.SearchService, and it's that sort of
  223.       Engine that is passed to this binding's observer as aEngine.
  224.  
  225.       In addition, browser.js fills two lists of autodetected search engines
  226.       (browser.engines and browser.hiddenEngines) as properties of
  227.       mCurrentBrowser.  Those lists contain unnamed JS objects of the form
  228.       { uri:, title:, icon: }, and that's what the searchbar uses to determine
  229.       whether to show any "Add <EngineName>" menu items in the drop-down.
  230.  
  231.       The two types of engines are currently related by their identifying
  232.       titles (the Engine object's 'name'), although that may change; see bug
  233.       335102.  -->
  234.  
  235.       <!-- If the engine that was just removed from the searchbox list was
  236.       autodetected on this page, move it to each browser's active list so it
  237.       will be offered to be added again. -->
  238.       <method name="offerNewEngine">
  239.         <parameter name="aEngine"/>
  240.         <body><![CDATA[
  241.           var allbrowsers = getBrowser().mPanelContainer.childNodes;
  242.           for (var tab = 0; tab < allbrowsers.length; tab++) {
  243.             var browser = getBrowser().getBrowserAtIndex(tab);
  244.             if (browser.hiddenEngines) {
  245.               // XXX This will need to be changed when engines are identified by
  246.               // URL rather than title; see bug 335102.
  247.               var removeTitle = aEngine.wrappedJSObject.name;
  248.               for (var i = 0; i < browser.hiddenEngines.length; i++) {
  249.                 if (browser.hiddenEngines[i].title == removeTitle) {
  250.                   if (!browser.engines)
  251.                     browser.engines = [];
  252.                   browser.engines.push(browser.hiddenEngines[i]);
  253.                   browser.hiddenEngines.splice(i, 1);
  254.                   break;
  255.                 }
  256.               }
  257.             }
  258.           }
  259.           BrowserSearch.updateSearchButton();
  260.         ]]></body>
  261.       </method>
  262.  
  263.       <!-- If the engine that was just added to the searchbox list was
  264.       autodetected on this page, move it to each browser's hidden list so it is
  265.       no longer offered to be added. -->
  266.       <method name="hideNewEngine">
  267.         <parameter name="aEngine"/>
  268.         <body><![CDATA[
  269.           var allbrowsers = getBrowser().mPanelContainer.childNodes;
  270.           for (var tab = 0; tab < allbrowsers.length; tab++) {
  271.             var browser = getBrowser().getBrowserAtIndex(tab);
  272.             if (browser.engines) {
  273.               // XXX This will need to be changed when engines are identified by
  274.               // URL rather than title; see bug 335102.
  275.               var removeTitle = aEngine.wrappedJSObject.name;
  276.               for (var i = 0; i < browser.engines.length; i++) {
  277.                 if (browser.engines[i].title == removeTitle) {
  278.                   if (!browser.hiddenEngines)
  279.                     browser.hiddenEngines = [];
  280.                   browser.hiddenEngines.push(browser.engines[i]);
  281.                   browser.engines.splice(i, 1);
  282.                   break;
  283.                 }
  284.               }
  285.             }
  286.           }
  287.           BrowserSearch.updateSearchButton();
  288.         ]]></body>
  289.       </method>
  290.  
  291.       <method name="updateDisplay">
  292.         <body><![CDATA[
  293.           var uri = this.currentEngine.iconURI;
  294.           if (uri)
  295.             this.setAttribute("src", uri.spec);
  296.           else
  297.             this.setAttribute("src", "");
  298.  
  299.           // Update current engine display
  300.           if (this.hasAttribute("empty")) 
  301.             this._textbox._displayCurrentEngine();
  302.  
  303.         ]]></body>
  304.       </method>
  305.  
  306.       <!-- Rebuilds the dynamic portion of the popup menu (i.e., the menu items
  307.            for new search engines that can be added to the available list).  This
  308.            is called each time the popup is shown.
  309.       -->
  310.       <method name="rebuildPopupDynamic">
  311.         <body><![CDATA[
  312.           var popup = this._popup;
  313.           // Clear any addengine menuitems, including addengine-item entries and
  314.           // the addengine-separator.  Work backward to avoid invalidating the
  315.           // indexes as items are removed.
  316.           var items = popup.childNodes;
  317.           for (var i = items.length - 1; i >= 0; i--) {
  318.             if (items[i].getAttribute("class").indexOf("addengine") != -1)
  319.               popup.removeChild(items[i]);
  320.           }
  321.  
  322.           var addengines = getBrowser().mCurrentBrowser.engines;
  323.           if (addengines && addengines.length > 0) {
  324.             const kXULNS =
  325.                "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
  326.  
  327.             // Find the (first) separator in the remaining menu, or the first item
  328.             // if no separators are present.
  329.             var insertLocation = popup.firstChild;
  330.             while (insertLocation.nextSibling &&
  331.                    insertLocation.localName != "menuseparator") {
  332.               insertLocation = insertLocation.nextSibling;
  333.             }
  334.             if (insertLocation.localName != "menuseparator")
  335.               insertLocation = popup.firstChild;
  336.  
  337.             var separator = document.createElementNS(kXULNS, "menuseparator");
  338.             separator.setAttribute("class", "addengine-separator");
  339.             popup.insertBefore(separator, insertLocation);
  340.  
  341.             // Insert the "add this engine" items.
  342.             for (var i = 0; i < addengines.length; i++) {
  343.               var menuitem = document.createElement("menuitem");
  344.               var engineInfo = addengines[i];
  345.               var labelStr =
  346.                   this._stringBundle.getFormattedString("cmd_addFoundEngine",
  347.                                                         [engineInfo.title]);
  348.               menuitem = document.createElementNS(kXULNS, "menuitem");
  349.               menuitem.setAttribute("class", "menuitem-iconic addengine-item");
  350.               menuitem.setAttribute("label", labelStr);
  351.               menuitem.setAttribute("uri", engineInfo.uri);
  352.               if (engineInfo.icon)
  353.                 menuitem.setAttribute("src", engineInfo.icon);
  354.               menuitem.setAttribute("title", engineInfo.title);
  355.               popup.insertBefore(menuitem, insertLocation);
  356.             }
  357.           }
  358.         ]]></body>
  359.       </method>
  360.  
  361.       <!-- Rebuilds the list of visible search engines in the menu.  Does not remove
  362.            or update any dynamic entries (i.e., "Add this engine" items) nor the
  363.            Manage Engines item.  This is called by the observer when the list of
  364.            visible engines, or the currently selected engine, has changed.
  365.       -->
  366.       <method name="rebuildPopup">
  367.         <body><![CDATA[
  368.           var popup = this._popup;
  369.  
  370.           // Clear the popup, down to the first separator
  371.           while (popup.firstChild && popup.firstChild.localName != "menuseparator")
  372.             popup.removeChild(popup.firstChild);
  373.  
  374.           const kXULNS =
  375.                "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
  376.  
  377.           // Prepend visible engines
  378.           this._engines = this.searchService.getVisibleEngines({ });
  379.           for (var i = this._engines.length - 1; i >= 0; --i) {
  380.             var menuitem = document.createElementNS(kXULNS, "menuitem");
  381.             menuitem.setAttribute("label", this._engines[i].name);
  382.             menuitem.setAttribute("id", this._engines[i].name);
  383.             menuitem.setAttribute("class", "menuitem-iconic searchbar-engine-menuitem");
  384.             // Since this menu is rebuilt by the observer method whenever a new
  385.             // engine is selected, the "selected" attribute does not need to be
  386.             // explicitly cleared anywhere.
  387.             if (this._engines[i] == this.currentEngine)
  388.               menuitem.setAttribute("selected", "true");
  389.             if (this._engines[i].iconURI)
  390.               menuitem.setAttribute("src", this._engines[i].iconURI.spec);
  391.             popup.insertBefore(menuitem, popup.firstChild);
  392.             menuitem.engine = this._engines[i];
  393.           }
  394.         ]]></body>
  395.       </method>
  396.  
  397.       <method name="openManager">
  398.         <parameter name="aEvent"/>
  399.         <body><![CDATA[
  400.           var wm =
  401.                 Components.classes["@mozilla.org/appshell/window-mediator;1"]
  402.                           .getService(Components.interfaces.nsIWindowMediator);
  403.  
  404.           var window = wm.getMostRecentWindow("Browser:SearchManager");
  405.           if (window)
  406.             window.focus()
  407.           else {
  408.             setTimeout(function () {
  409.               openDialog("chrome://browser/content/search/engineManager.xul",
  410.                          "_blank", "chrome,dialog,modal,centerscreen");
  411.             }, 0);
  412.           }
  413.         ]]></body>
  414.       </method>
  415.  
  416.       <!-- Because this may be called from a command handler, where event.target is
  417.       not the correct target for the command, it takes a target rather than an
  418.       event as a parameter.  Note that because of the engine-list maintenance
  419.       performed in this function, it should not be used in a way that leaves the
  420.       menu open after this function has been called (or if it is, be sure to call
  421.       rebuildPopupDynamic afterward).
  422.       -->
  423.       <method name="onEnginePopupCommand">
  424.         <parameter name="aTarget"/>
  425.         <body><![CDATA[
  426.           if (aTarget.getAttribute("class").indexOf("addengine-item") != -1) {
  427.             var searchService =
  428.                 Components.classes["@mozilla.org/browser/search-service;1"]
  429.                           .getService(Components.interfaces.nsIBrowserSearchService);
  430.             // We only detect OpenSearch files
  431.             var type = Components.interfaces.nsISearchEngine.DATA_XML;
  432.             searchService.addEngine(aTarget.getAttribute("uri"), type,
  433.                                     aTarget.getAttribute("src"), false);
  434.           }
  435.           else if (aTarget.engine)
  436.             this.currentEngine = aTarget.engine;
  437.  
  438.           this.focus();
  439.           this.select();
  440.         ]]></body>
  441.       </method>
  442.  
  443.       <method name="selectEngine">
  444.         <parameter name="aEvent"/>
  445.         <parameter name="isNextEngine"/>
  446.         <body><![CDATA[
  447.           // Find the new index
  448.           var newIndex = this._engines.indexOf(this.currentEngine);
  449.           newIndex += (isNextEngine) ? 1 : -1;
  450.  
  451.           if (newIndex >= 0 && newIndex < this._engines.length)
  452.             this.currentEngine = this._engines[newIndex];
  453.  
  454.           aEvent.preventDefault();
  455.           aEvent.stopPropagation();
  456.         ]]></body>
  457.       </method>
  458.  
  459.       <method name="handleSearchCommand">
  460.         <parameter name="aEvent"/>
  461.         <body><![CDATA[
  462.           var textBox = this._textbox;
  463.           var textValue = textBox.value;
  464.           // Ignore greyed-out hint text in "empty" searchboxes.
  465.           if (this.getAttribute("empty") == "true")
  466.             textValue = "";
  467.  
  468.           // Save the current value in the form history
  469.           if (textValue) {
  470.             textBox._formHistSvc.addEntry(textBox.getAttribute("autocompletesearchparam"),
  471.                                           textValue);
  472.           }
  473.  
  474.           // Always open in a new tab on a middle-click; otherwise examine the
  475.           // preference and the alt key.  If the user chose an autocomplete
  476.           // entry with the mouse, aEvent will be null, so treat it as no alt key.
  477.           var newTab = (aEvent && aEvent.button == 1);
  478.           if (!newTab) {
  479.             var newTabPref = textBox._prefBranch.getBoolPref("browser.search.openintab");
  480.             newTab = ((aEvent && aEvent.altKey) ^ newTabPref);
  481.           }
  482.           this.doSearch(textValue, newTab);
  483.         ]]></body>
  484.       </method>
  485.  
  486.       <method name="doSearch">
  487.         <parameter name="aData"/>
  488.         <parameter name="aInNewTab"/>
  489.         <body><![CDATA[
  490.           var metrics = Components.classes['@flock.com/metrics-service;1']
  491.             .getService(Components.interfaces.flockIMetricsService);
  492.           metrics.reportCount('search ' + this.currentEngine.name);
  493.  
  494.           var postData = null;
  495.  
  496.           // null parameter below specifies HTML response for search
  497.           var submission = this.currentEngine.getSubmission(aData, null);
  498.           if (submission) {
  499.             var url = submission.uri.spec;
  500.             postData = submission.postData;
  501.           }
  502.  
  503.           if (aInNewTab) {
  504.             content.focus();
  505.             getBrowser().loadOneTab(url, null, null, postData, false, false);
  506.             if (gURLBar)
  507.               gURLBar.value = url;
  508.           }
  509.           else
  510.             loadURI(url, null, postData, false);
  511.           content.focus();
  512.         ]]></body>
  513.       </method>
  514.  
  515.     </implementation>
  516.  
  517.     <handlers>
  518.       <handler event="click"><![CDATA[
  519.         const target = event.originalTarget;
  520.         var anonid = target.getAttribute("anonid");
  521.         /* We can't use checkForMiddleClick() from utilityOverlay.js here
  522.            because the button is using a command handler rather than an oncommand
  523.            attribute.  The middle-click behavior itself (i.e., opening the search 
  524.            in a new tab) is handled in handleSearchCommand().
  525.         */
  526.         if (anonid == "search-go-button" && event.button == 1)
  527.           this.handleSearchCommand(event);
  528.       ]]></handler>
  529.  
  530.       <handler event="command"><![CDATA[
  531.         const target = event.originalTarget;
  532.         var anonid = target.getAttribute("anonid");
  533.         if (anonid == "search-go-button")
  534.           this.handleSearchCommand(event);
  535.         else if (anonid == "open-engine-manager")
  536.           openPreferences('paneSearching'); // open the flock search preferences dialog
  537.           //this.openManager(event);
  538.  
  539.         else if (target.getAttribute("class").indexOf("addengine-item") != -1 ||
  540.                  target.engine)
  541.           this.onEnginePopupCommand(target);
  542.       ]]></handler>
  543.  
  544.       <handler event="popupshowing" action="this.rebuildPopupDynamic();
  545.                                             this._engineButton.setAttribute('open', true);"/>
  546.       <handler event="popuphiding" action="this._engineButton.removeAttribute('open');"/>
  547.     </handlers>
  548.   </binding>
  549.  
  550.   <binding id="searchbar-textbox"
  551.       extends="chrome://global/content/bindings/autocomplete.xml#autocomplete">
  552.     <implementation implements="nsIObserver">
  553.       <constructor><![CDATA[
  554.         if (this._getParentSearchbar().parentNode.parentNode.localName ==
  555.             "toolbarpaletteitem")
  556.           return;
  557.         setTimeout(function(a) { a.initialize(); }, 0, this);
  558.       ]]></constructor>
  559.  
  560.       <destructor><![CDATA[
  561.           var ps2 = Components.classes["@mozilla.org/preferences-service;1"]
  562.                               .getService(Components.interfaces.nsIPrefBranch2);
  563.           ps2.removeObserver("browser.search.suggest.enabled", this);
  564.  
  565.         // Because XBL and the customize toolbar code interacts poorly,
  566.         // there may not be anything to remove here
  567.         try {
  568.           this.controllers.removeController(this.searchbarController);
  569.         } catch (ex) { }
  570.       ]]></destructor>
  571.  
  572.       <field name="_stringBundle"/>
  573.       <field name="_formHistSvc"/>
  574.       <field name="_prefBranch"/>
  575.       <field name="_suggestMenuItem"/>
  576.       <field name="_suggestEnabled"/>
  577.  
  578.       <method name="initialize">
  579.         <body><![CDATA[
  580.           // Initialize fields
  581.           this._stringBundle = this._getParentSearchbar()._stringBundle;
  582.           this._formHistSvc =
  583.                    Components.classes["@mozilla.org/satchel/form-history;1"]
  584.                              .getService(Components.interfaces.nsIFormHistory2);
  585.           this._prefBranch =
  586.                     Components.classes["@mozilla.org/preferences-service;1"]
  587.                               .getService(Components.interfaces.nsIPrefBranch);
  588.           this._suggestEnabled =
  589.               this._prefBranch.getBoolPref("browser.search.suggest.enabled");
  590.  
  591.           if (this._prefBranch.getBoolPref("browser.urlbar.clickSelectsAll"))
  592.             this.setAttribute("clickSelectsAll", true);
  593.  
  594.           // Add items to context menu and attach controller to handle them
  595.           var textBox = document.getAnonymousElementByAttribute(this,
  596.                                                 "anonid", "textbox-input-box");
  597.           var cxmenu = document.getAnonymousElementByAttribute(textBox,
  598.                                             "anonid", "input-box-contextmenu");
  599.  
  600.           var element = document.createElementNS(XUL_NS, "menuseparator");
  601.           cxmenu.appendChild(element);
  602.           element = document.createElementNS(XUL_NS, "menuitem");
  603.           var label = this._stringBundle.getString("cmd_clearHistory");
  604.           var akey = this._stringBundle.getString("cmd_clearHistory_accesskey");
  605.           element.setAttribute("label", label);
  606.           element.setAttribute("accesskey", akey);
  607.           element.setAttribute("cmd", "cmd_clearhistory");
  608.  
  609.           cxmenu.appendChild(element);
  610.  
  611.           element = document.createElementNS(XUL_NS, "menuitem");
  612.           label = this._stringBundle.getString("cmd_showSuggestions");
  613.           akey = this._stringBundle.getString("cmd_showSuggestions_accesskey");
  614.           element.setAttribute("anonid", "toggle-suggest-item");
  615.           element.setAttribute("label", label);
  616.           element.setAttribute("accesskey", akey);
  617.           element.setAttribute("cmd", "cmd_togglesuggest");
  618.           element.setAttribute("type", "checkbox");
  619.           element.setAttribute("checked", this._suggestEnabled);
  620.           element.setAttribute("autocheck", "false");
  621.  
  622.           this._suggestMenuItem = element;
  623.           cxmenu.appendChild(element);
  624.  
  625.           this.controllers.appendController(this.searchbarController);
  626.  
  627.           // Add observer for suggest preference
  628.           var ps2 = Components.classes["@mozilla.org/preferences-service;1"]
  629.                               .getService(Components.interfaces.nsIPrefBranch2);
  630.           ps2.addObserver("browser.search.suggest.enabled", this, false);
  631.         ]]></body>
  632.       </method>
  633.  
  634.       <method name="observe">
  635.         <parameter name="aSubject"/>
  636.         <parameter name="aTopic"/>
  637.         <parameter name="aData"/>
  638.         <body><![CDATA[
  639.           if (aTopic == "nsPref:changed") {
  640.             this._suggestEnabled =
  641.               this._prefBranch.getBoolPref("browser.search.suggest.enabled");
  642.             this._suggestMenuItem.setAttribute("checked", this._suggestEnabled);
  643.           }
  644.         ]]></body>
  645.       </method>
  646.  
  647.       <method name="openSearch">
  648.         <body>
  649.           <![CDATA[
  650.             // Don't open search popup if history popup is open
  651.             if (!this.popupOpen) {
  652.               this._getParentSearchbar()._popup.click();
  653.               return false;
  654.             }
  655.             return true;
  656.           ]]>
  657.         </body>
  658.       </method>
  659.  
  660.       <!-- Returns the closest parent that is a searchbar element.
  661.            If no searchbar element is found, returns null.
  662.       -->
  663.       <method name="_getParentSearchbar">
  664.         <body><![CDATA[
  665.           var searchbar = this.parentNode;
  666.           while (searchbar) {
  667.             if (searchbar.nodeName == "searchbar")
  668.               break;
  669.             searchbar = searchbar.parentNode;
  670.           }
  671.           return searchbar;
  672.         ]]></body>
  673.       </method>
  674.  
  675.       <!-- Displays a grayed-out hint string containing the name of the
  676.            current search engine in the search text box.  (It makes it gray
  677.            by setting an empty="true" attribute on the searchbox element.)
  678.       -->
  679.       <method name="_displayCurrentEngine">
  680.         <body><![CDATA[
  681.           var searchbar = this._getParentSearchbar();
  682.  
  683.           // This section is a wee bit hacky; without the timeout, the CSS
  684.           // style corresponding to the "empty" attribute doesn't kick in
  685.           // until the text has changed, leading to an unpleasant moment
  686.           // where the engine name flashes black before turning gray.
  687.           searchbar.setAttribute("empty", "true");
  688.  
  689.           var searchTextbox = this;
  690.           setTimeout(function() {
  691.             if (searchbar.getAttribute("empty") == "true")
  692.               searchTextbox.value = searchbar.currentEngine.name;
  693.           }, 0);
  694.         ]]></body>
  695.       </method>
  696.  
  697.       <!-- overload |onTextEntered| in autocomplete.xml -->
  698.       <method name="onTextEntered">
  699.         <parameter name="aEvent"/>
  700.         <body><![CDATA[
  701.           var evt = aEvent || this.mEnterEvent;
  702.           this._getParentSearchbar().handleSearchCommand(evt);
  703.           this.mEnterEvent = null;
  704.         ]]></body>
  705.       </method>
  706.  
  707.       <!-- nsIController -->
  708.       <field name="searchbarController" readonly="true"><![CDATA[({
  709.         _self: this,
  710.         supportsCommand: function(aCommand) {
  711.           return aCommand == "cmd_clearhistory" ||
  712.                  aCommand == "cmd_togglesuggest";
  713.         },
  714.  
  715.         isCommandEnabled: function(aCommand) {
  716.           if (aCommand == "cmd_clearhistory") {
  717.             var param = this._self.getAttribute("autocompletesearchparam");
  718.             return this._self._formHistSvc.nameExists(param);
  719.           }
  720.           return true;
  721.         },
  722.  
  723.         doCommand: function (aCommand) {
  724.           switch (aCommand) {
  725.             case "cmd_clearhistory":
  726.               var param = this._self.getAttribute("autocompletesearchparam");
  727.               this._self._formHistSvc.removeEntriesForName(param);
  728.               this._self.value = "";
  729.               break;
  730.             case "cmd_togglesuggest":
  731.               // The pref observer will update _suggestEnabled and the menu
  732.               // checkmark.
  733.               this._self._prefBranch.setBoolPref("browser.search.suggest.enabled",
  734.                                                  !this._self._suggestEnabled);
  735.               break;
  736.             default:
  737.               // do nothing with unrecognized command
  738.           }
  739.         }
  740.       })]]></field>
  741.  
  742.       <!-- DND Observer -->
  743.       <field name="searchbarDNDObserver" readonly="true"><![CDATA[({
  744.         mOuter: this,
  745.  
  746.         onDrop: function (aEvent, aXferData, aDragSession) {
  747.           var data = transferUtils.retrieveURLFromData(aXferData.data,
  748.                          aXferData.flavour.contentType);
  749.           if (data) {
  750.             // Remove the search bar's empty attribute, since we're setting
  751.             // a value without focusing the textbox. If it's not empty, this
  752.             // won't do anything. This can be removed if bug 280635 is fixed.
  753.             this.mOuter._getParentSearchbar().removeAttribute("empty");
  754.             this.mOuter.value = data;
  755.  
  756.             this.mOuter.onTextEntered(aEvent);
  757.           }
  758.         },
  759.  
  760.         getSupportedFlavours: function () {
  761.           var flavourSet = new FlavourSet();
  762.  
  763.           flavourSet.appendFlavour("text/unicode");
  764.           flavourSet.appendFlavour("text/x-moz-url");
  765.           flavourSet.appendFlavour("application/x-moz-file", "nsIFile");
  766.           return flavourSet;
  767.         }
  768.       })]]></field>
  769.     </implementation>
  770.  
  771.     <handlers>
  772.       <handler event="keypress" keycode="vk_up" modifiers="accel"
  773.                phase="capturing"
  774.                action="this._getParentSearchbar().selectEngine(event, false);"/>
  775.  
  776.       <handler event="keypress" keycode="vk_down" modifiers="accel"
  777.                phase="capturing"
  778.                action="this._getParentSearchbar().selectEngine(event, true);"/>
  779.  
  780.       <handler event="keypress" keycode="vk_down" modifiers="alt"
  781.                phase="capturing"
  782.                action="return this.openSearch();"/>
  783.  
  784.       <handler event="keypress" keycode="vk_up" modifiers="alt"
  785.                phase="capturing"
  786.                action="return this.openSearch();"/>
  787.  
  788.       <handler event="keypress" keycode="vk_f4"
  789.                phase="capturing"
  790.                action="return this.openSearch();"/>
  791.  
  792.       <handler event="dragdrop" phase="capturing">
  793.         nsDragAndDrop.drop(event, this.searchbarDNDObserver);
  794.       </handler>
  795.  
  796.       <handler event="focus" phase="capturing"><![CDATA[
  797.         var searchbar = this._getParentSearchbar();
  798.         if (searchbar.getAttribute("empty") == "true") {
  799.           searchbar.removeAttribute("empty");
  800.           this.value = "";
  801.         }
  802.       ]]></handler>
  803.  
  804.       <handler event="blur" phase="capturing"><![CDATA[
  805.         var searchbar = this._getParentSearchbar();
  806.         if (this.value == "")
  807.           this._displayCurrentEngine();
  808.       ]]></handler>
  809.  
  810.     </handlers>
  811.   </binding>
  812.  
  813.   <binding id="searchbar-engine-button"
  814.            extends="chrome://browser/content/search/search.xml#searchbar-base">
  815.     <content>
  816.       <xul:stack flex="1" class="searchbar-engine-button-stack">
  817.         <xul:vbox>
  818.           <xul:image class="searchbar-engine-button-top searchbar-engine-button-bkgnd"/>
  819.           <xul:image flex="1"
  820.                      class="searchbar-engine-button-mid-top searchbar-engine-button-bkgnd"/>
  821.           <xul:image flex="1"
  822.                      class="searchbar-engine-button-mid-bottom searchbar-engine-button-bkgnd"/>
  823.           <xul:image class="searchbar-engine-button-bottom searchbar-engine-button-bkgnd"/>
  824.         </xul:vbox>
  825.         <xul:hbox align="center"
  826.                   class="searchbar-engine-image-container">
  827.           <xul:image class="searchbar-engine-image" xbl:inherits="src"/>
  828.           <xul:image class="searchbar-dropmarker-image"/>
  829.         </xul:hbox>
  830.       </xul:stack>
  831.       <children/>
  832.     </content>
  833.   </binding>
  834.  
  835. </bindings>
  836.